﻿using System;
using System.Threading;
using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.Practices.EnterpriseLibrary.Logging;

namespace Paragon.Logging
{
    public class Logger
    {
        public const string LOGGER_FULLNAME = "LoggerFullName";

        internal Logger(string name)
        {
            Name = name;
        }

        public string Name { get; set; }

        private void Log(int eventId, TraceEventType level, object message, Exception ex, params object[] args)
        {
            LogEntry entry = new LogEntry();

            // Prepares the log message
            if (args != null && args.Length > 0)
            {
                string formattedMessage = string.Empty;
                try
                {
                    if(message != null)
                        formattedMessage = message.ToString().Para(args);
                }
                catch (Exception error)
                {
                    Error("Error logging message, invalid format string: ", error);
                    formattedMessage = message.ToString();
                }


                entry.Message = formattedMessage;
            }
            else
            {
                entry.Message = message.ToString();
            }

            if (ex != null)
            {
                //entry.Message += "\r\n" + ex.ToString();
                entry.ExtendedProperties[EXCEPTION_KEY] = ex;
            }

            entry.Priority = 5;//(int)level;
            entry.Categories.Clear();
            entry.Categories.Add(level.ToString());
            entry.EventId = eventId;
            entry.Severity = level;

            try
            {
                Exception copyException = ThreadContext.CurrentContext.CopyTo(entry.ExtendedProperties);
                if (copyException != null)
                {
                    Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write(new LogEntry() { Severity = TraceEventType.Error, Title = "Logging Copy Error", Message = "Logging copy error: \r\n" + copyException.ToString() });
                }

            }
            catch (Exception logException)
            {
                Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write(new LogEntry() { Severity = TraceEventType.Error, Title = "Logging Copy Error", Message = "Logging copy error: \r\n" + logException.ToString() });
            }

            entry.ExtendedProperties[LOGGER_FULLNAME] = Name;

            try
            {
                Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write(entry);
            }
            catch (Exception logException)
            {
                Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write(new LogEntry() { Severity = TraceEventType.Error, Title = "Logging Error", Message = "Logging error: \r\n" + logException.ToString() });
            }
        }

        #region Common Keys

        public const string EXCEPTION_KEY = "Exception";
        public const string IP_ADDRESS_KEY = "IpAddress";
        public const string URL_KEY = "Url";
        public const string USERNAME_KEY = "Username";
        public const string SESSION_ID_KEY = "SessionId";

        public const string HTTP_METHOD = "HttpMethod";
        public const string REFERRER = "Referrer";
        public const string USER_AGENT = "UserAgent";
        public const string QUERY_STRING = "QueryString";

        #endregion

        #region "Generated Methods"
        public void Critical(object message)
        {
            Critical(message, null, null);
        }

        public void Critical(object message, Exception ex)
        {
            Critical(message, ex, null);
        }

        public void Critical(object message, params object[] args)
        {
            Critical(message, null, args);
        }

        public void Critical(object message, Exception ex, params object[] args)
        {
            Critical(5000 + (int)TraceEventType.Critical, message, ex, args);
        }

        public void Critical(int eventId, object message, Exception ex, params object[] args)
        {
            Log(eventId, TraceEventType.Critical, message, ex, args);
        }

        public void Error(object message)
        {
            Error(message, null, null);
        }

        public void Error(object message, Exception ex)
        {
            Error(message, ex, null);
        }

        public void Error(object message, params object[] args)
        {
            Error(message, null, args);
        }

        public void Error(object message, Exception ex, params object[] args)
        {
            Error(5000 + (int)TraceEventType.Error, message, ex, args);
        }

        public void Error(int eventId, object message, Exception ex, params object[] args)
        {
            Log(eventId, TraceEventType.Error, message, ex, args);
        }

        public void Warning(object message)
        {
            Warning(message, null, null);
        }

        public void Warning(object message, Exception ex)
        {
            Warning(message, ex, null);
        }

        public void Warning(object message, params object[] args)
        {
            Warning(message, null, args);
        }

        public void Warning(object message, Exception ex, params object[] args)
        {
            Warning(5000 + (int)TraceEventType.Warning, message, ex, args);
        }

        public void Warning(int eventId, object message, Exception ex, params object[] args)
        {
            Log(eventId, TraceEventType.Warning, message, ex, args);
        }

        public void Information(object message)
        {
            Information(message, null, null);
        }

        public void Information(object message, Exception ex)
        {
            Information(message, ex, null);
        }

        public void Information(object message, params object[] args)
        {
            Information(message, null, args);
        }

        public void Information(object message, Exception ex, params object[] args)
        {
            Information(5000 + (int)TraceEventType.Information, message, ex, args);
        }

        public void Information(int eventId, object message, Exception ex, params object[] args)
        {
            Log(eventId, TraceEventType.Information, message, ex, args);
        }

        public void Verbose(object message)
        {
            Verbose(message, null, null);
        }

        public void Verbose(object message, Exception ex)
        {
            Verbose(message, ex, null);
        }

        public void Verbose(object message, params object[] args)
        {
            Verbose(message, null, args);
        }

        public void Verbose(object message, Exception ex, params object[] args)
        {
            Verbose(5000 + (int)TraceEventType.Verbose, message, ex, args);
        }

        public void Verbose(int eventId, object message, Exception ex, params object[] args)
        {
            Log(eventId, TraceEventType.Verbose, message, ex, args);
        }

        public void Start(object message)
        {
            Start(message, null, null);
        }

        public void Start(object message, Exception ex)
        {
            Start(message, ex, null);
        }

        public void Start(object message, params object[] args)
        {
            Start(message, null, args);
        }

        public void Start(object message, Exception ex, params object[] args)
        {
            Start(5000 + (int)TraceEventType.Start, message, ex, args);
        }

        public void Start(int eventId, object message, Exception ex, params object[] args)
        {
            Log(eventId, TraceEventType.Start, message, ex, args);
        }

        public void Stop(object message)
        {
            Stop(message, null, null);
        }

        public void Stop(object message, Exception ex)
        {
            Stop(message, ex, null);
        }

        public void Stop(object message, params object[] args)
        {
            Stop(message, null, args);
        }

        public void Stop(object message, Exception ex, params object[] args)
        {
            Stop(5000 + (int)TraceEventType.Stop, message, ex, args);
        }

        public void Stop(int eventId, object message, Exception ex, params object[] args)
        {
            Log(eventId, TraceEventType.Stop, message, ex, args);
        }

        public void Suspend(object message)
        {
            Suspend(message, null, null);
        }

        public void Suspend(object message, Exception ex)
        {
            Suspend(message, ex, null);
        }

        public void Suspend(object message, params object[] args)
        {
            Suspend(message, null, args);
        }

        public void Suspend(object message, Exception ex, params object[] args)
        {
            Suspend(5000 + (int)TraceEventType.Suspend, message, ex, args);
        }

        public void Suspend(int eventId, object message, Exception ex, params object[] args)
        {
            Log(eventId, TraceEventType.Suspend, message, ex, args);
        }

        public void Resume(object message)
        {
            Resume(message, null, null);
        }

        public void Resume(object message, Exception ex)
        {
            Resume(message, ex, null);
        }

        public void Resume(object message, params object[] args)
        {
            Resume(message, null, args);
        }

        public void Resume(object message, Exception ex, params object[] args)
        {
            Resume(5000 + (int)TraceEventType.Resume, message, ex, args);
        }

        public void Resume(int eventId, object message, Exception ex, params object[] args)
        {
            Log(eventId, TraceEventType.Resume, message, ex, args);
        }

        public void Transfer(object message)
        {
            Transfer(message, null, null);
        }

        public void Transfer(object message, Exception ex)
        {
            Transfer(message, ex, null);
        }

        public void Transfer(object message, params object[] args)
        {
            Transfer(message, null, args);
        }

        public void Transfer(object message, Exception ex, params object[] args)
        {
            Transfer(5000 + (int)TraceEventType.Transfer, message, ex, args);
        }

        public void Transfer(int eventId, object message, Exception ex, params object[] args)
        {
            Log(eventId, TraceEventType.Transfer, message, ex, args);
        }
        #endregion
    }
}
